/*
 * Copyright (c) 2024 Black Sesame Technologies
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "dal_fastdds/utils/log.hpp"
#include "dal_fastdds/entity_impl/DalDomainParticipantImpl.hpp"

DalDomainParticipantImpl::DalDomainParticipantImpl(DomainParticipant* fastdds_participant,
                                                   DomainParticipantListenerImpl* listener)
{
    fastdds_participant_ = fastdds_participant;
    listener_ = listener;

    cs_pub_ = nullptr;
    cs_sub_ = nullptr;
    is_cs_pubsub_ready_.store(false);
}

DalDomainParticipantImpl::~DalDomainParticipantImpl()
{
}

bool DalDomainParticipantImpl::Clear()
{
    if (!DeleteCSPubSub()) {
        LOG_ERROR_WITH_LOCATION() << "delete cs pubsub failed" << LOG_ENDL;
        return false;
    }

    if (!DeleteCSTopics()) {
        LOG_ERROR_WITH_LOCATION() << "delete cs topics failed" << LOG_ENDL;
        return false;
    }

    return true;
}

DomainParticipant*& DalDomainParticipantImpl::FastddsDomainParticipant()
{
    return fastdds_participant_;
}

bool DalDomainParticipantImpl::CreateCSPubSub()
{
    if (is_cs_pubsub_ready_.load())
        return true;

    std::lock_guard<std::mutex> lock(cs_pubsub_mutex_);
    if (is_cs_pubsub_ready_.load())
        return true;

    if (!fastdds_participant_) {
        LOG_ERROR_WITH_LOCATION() << "domain participant is null" << LOG_ENDL;
        return false;
    }

    cs_pub_ =
        fastdds_participant_->create_publisher(PUBLISHER_QOS_DEFAULT, nullptr, StatusMask::none());
    if (!cs_pub_) {
        LOG_ERROR_WITH_LOCATION() << "create cs publisher failed" << LOG_ENDL;
        return false;
    }

    cs_sub_ = fastdds_participant_->create_subscriber(
        SUBSCRIBER_QOS_DEFAULT, nullptr, StatusMask::none());
    if (!cs_sub_) {
        LOG_ERROR_WITH_LOCATION() << "create cs subscriber failed" << LOG_ENDL;
        return false;
    }

    is_cs_pubsub_ready_.store(true);

    return true;
}
bool DalDomainParticipantImpl::DeleteCSPubSub()
{
    if (!is_cs_pubsub_ready_.load())
        return true;

    if (!fastdds_participant_) {
        LOG_ERROR_WITH_LOCATION() << "domain participant is null" << LOG_ENDL;
        return false;
    }

    std::lock_guard<std::mutex> lock(cs_pubsub_mutex_);
    if (!is_cs_pubsub_ready_.load())
        return true;

    if (!fastdds_participant_->delete_publisher(cs_pub_)) {
        LOG_ERROR_WITH_LOCATION() << "delete cs publisher failed" << LOG_ENDL;
        return false;
    }

    if (!fastdds_participant_->delete_subscriber(cs_sub_)) {
        LOG_ERROR_WITH_LOCATION() << "delete cs subscriber failed" << LOG_ENDL;
        return false;
    }

    is_cs_pubsub_ready_.store(false);

    return true;
}

Publisher* DalDomainParticipantImpl::CSPublisher()
{
    if (!is_cs_pubsub_ready_.load())
        return nullptr;

    return cs_pub_;
}

Subscriber* DalDomainParticipantImpl::CSSubscriber()
{
    if (!is_cs_pubsub_ready_.load())
        return nullptr;

    return cs_sub_;
}

void DalDomainParticipantImpl::AddCSTopic(Topic* topic)
{
    std::lock_guard<std::mutex> lock(cs_topics_mutex_);
    cs_topics_.push_back(topic);
}
bool DalDomainParticipantImpl::DeleteCSTopics()
{
    for (auto topic : cs_topics_) {
        if (!fastdds_participant_->delete_topic(topic)) {
            LOG_ERROR_WITH_LOCATION() << "delete cs topic failed" << LOG_ENDL;
            return false;
        }
    }
    return true;
}